﻿using System.Collections.Concurrent;
using System.Collections.ObjectModel;
using System.Runtime.InteropServices;
using System.Windows;
using VideoTools.Commands;
using VideoTools.vo;
using TaskStatus = VideoTools.vo.TaskStatus;
namespace VideoTools.Tasks
{
    public class SplitVideoTaskQueueManager : NotifyPropertyBase
    {
        private static volatile SplitVideoTaskQueueManager _instance;
        private static readonly object SyncRoot = new object();
        public static SplitVideoTaskQueueManager Instance
        {
            get
            {
                if (_instance == null)
                {
                    lock (SyncRoot)
                    {
                        if (_instance == null)
                        {
                            _instance = new SplitVideoTaskQueueManager();
                        }
                    }
                }

                return _instance;
            }
        }
        private SplitVideoTaskQueueManager()
        {

        }
        private readonly ObservableCollection<SplitVideoTaskItem> _tasks = new ObservableCollection<SplitVideoTaskItem>();
        public IReadOnlyCollection<SplitVideoTaskItem> Tasks => _tasks;
        private DateTime startTime;
        private int _maxConcurrentTasks = 1;
        public int MaxConcurrentTasks
        {
            get => _maxConcurrentTasks;
            //set
            //{
            //    SetProperty(ref _maxConcurrentTasks, value);
            //    StartProcessing(); // 当并发数改变时尝试启动新任务
            //}
        }

        private IList<SplitVideoTaskItem> _SelectedTasks = new List<SplitVideoTaskItem>();
        public IList<SplitVideoTaskItem> SelectedTasks
        {
            get { return _SelectedTasks; }
            set
            {
                SetProperty(ref _SelectedTasks, value);
                SetBackgroundColor();
            }
        }
        private readonly ConcurrentDictionary<SplitVideoTaskItem, bool> _runningTasks = new ConcurrentDictionary<SplitVideoTaskItem, bool>();
        public int RunningTaskCount => _runningTasks.Count;

        public void AddTask(SplitVideoTaskItem taskItem, Action<CancellationToken, IProgress<double>, SplitVideoTaskItem> taskAction, Action<CancellationToken, SplitVideoTaskItem> taskActionBefore, Action<CancellationToken, SplitVideoTaskItem> taskActionAfter)
        {
            var existingDownloads = _tasks
                .Where(d => d.Path == taskItem.Path)
                .FirstOrDefault();
            if (existingDownloads is not null)
                return;

            

            var progress = new Progress<double>(p => taskItem.Progress = p);
            taskItem.TaskActionAfter = () =>
            {
                taskActionAfter(taskItem.CancellationTokenSource.Token, taskItem);
            };
            taskItem.TaskActionBefore = () =>
            {
                taskActionBefore(taskItem.CancellationTokenSource.Token, taskItem);
            };
            taskItem.TaskAction = () =>
            {
                taskAction(taskItem.CancellationTokenSource.Token, progress,taskItem);
            };

            _tasks.Add(taskItem);
            SetBackgroundColor();
        }
        public void SetBackgroundColor()
        {
            for (int i = 0; i < _tasks.Count; i++)
            {
                var line = _tasks[i];
                if (SelectedTasks.Contains(line))
                {
                    line.BgColour = ListBoxLineBackground.Selected;
                }
                else
                {
                    if (line.Status == TaskStatus.Completed)
                    {
                        line.BgColour =
                            (i % 2 == 0) ? ListBoxLineBackground.DoneEven : ListBoxLineBackground.DoneOdd;
                    }
                    else
                    {
                        line.BgColour =
                            (i % 2 == 0) ? ListBoxLineBackground.Even : ListBoxLineBackground.Odd;
                    }
                }
            }
        }

        public void StartProcessing()
        {
            // 计算可以启动的新任务数量
            int availableSlots = MaxConcurrentTasks - RunningTaskCount;
            if (availableSlots > MaxConcurrentTasks)
            {
                availableSlots = MaxConcurrentTasks;
            }
            for (int i = 0; i < availableSlots; i++)
            {
                var nextTask = _tasks.FirstOrDefault(t => t.Status == TaskStatus.Pending);
                if (nextTask == null)
                {

                    SplitVideoCommands.Instance.CurrentTask = null;
                    SplitVideoCommands.Instance.BatchTabItemEnabled = true;
                    SplitVideoCommands.Instance.OpenVideoButtonEnabled = true;
                    SplitVideoCommands.Instance.DeviceTypeEnable = true;
                    SplitVideoCommands.Instance.CompatibleModeEnabled = true;
                    SplitVideoCommands.Instance.StartTimeEnabled = true;
                    SplitVideoCommands.Instance.EndTimeEnabled = true;
                    SplitVideoCommands.Instance.DoitButtonEnabled = true;
                    SplitVideoCommands.Instance.StopButtonEnabled = false;
                    SplitVideoCommands.Instance.SpendTimeVisibility = Visibility.Hidden;
                    SplitVideoCommands.Instance.ProgressVisibility = Visibility.Hidden;
                    if (FFmpegCommands.Instance.ShutDownOnDoneAll)
                    {
                        shutDown();
                    }
                    break;
                }
                SplitVideoCommands.Instance.CurrentTask = nextTask;
                StartTask(nextTask);
            }
        }
        public void DeleteSelected()
        {
            var list = _tasks.Where(t => SelectedTasks.Contains(t)).ToList();
            foreach (var task in list)
            {
                _tasks.Remove(task);
            }
            SelectedTasks = new List<SplitVideoTaskItem>();
            SetBackgroundColor();

        }
        private async void StartTask(SplitVideoTaskItem task)
        {
            task.Status = TaskStatus.Running;
            _runningTasks[task] = true;
            OnPropertyChanged(nameof(RunningTaskCount));
            startTime = DateTime.Now;

            try
            {
                await Task.Run(() =>
                {
                    task.taskStartTime = DateTime.Now;
                    task.TaskActionBefore?.Invoke();
                    task.TaskAction?.Invoke();
                    task.TaskActionAfter?.Invoke();
                    _runningTasks.TryRemove(task, out _);
                    OnPropertyChanged(nameof(RunningTaskCount));
                    StartProcessing(); // 任务完成后尝试启动新任务
                });

                task.Status = TaskStatus.Completed;
            }
            catch (OperationCanceledException)
            {
                task.Status = TaskStatus.Failed;
                task.Progress = 0;
            }
            catch
            {
                task.Status = TaskStatus.Failed;
            }
            finally
            {

            }
        }

        public void StopAllTasks()
        {
            foreach (var task in _tasks)
            {
                if (task.Status == TaskStatus.Running || task.Status == TaskStatus.Pending)
                {
                    task.Cancel();
                }
            }
            _runningTasks.Clear();
            OnPropertyChanged(nameof(RunningTaskCount));
        }

        public void ClearCompletedTasks()
        {
            var completedTasks = _tasks.Where(t => t.Status == TaskStatus.Completed).ToList();
            foreach (var task in completedTasks)
            {
                _tasks.Remove(task);
            }
            SetBackgroundColor();
        }
        public void ClearTasks()
        {
            _tasks.Clear();
            SelectedTasks = new List<SplitVideoTaskItem>();
        }








        private const int SE_PRIVILEGE_ENABLED = 0x00000002;
        private const int TOKEN_QUERY = 0x00000008;
        private const int TOKEN_ADJUST_PRIVILEGES = 0x00000020;
        private const string SE_SHUTDOWN_NAME = "SeShutdownPrivilege";
        [Flags]
        public enum ExitWindows : uint
        {
            ShutDown = 0x01
        }

        [Flags]
        private enum ShutdownReason : uint
        {
            MajorOther = 0x00000000
        }
        [StructLayout(LayoutKind.Sequential, Pack = 1)]
        private struct TokPriv1Luid
        {
            public int Count;
            public long Luid;
            public int Attr;
        }
        private void shutDown()
        {
            TokPriv1Luid tp;
            IntPtr hproc = GetCurrentProcess();
            IntPtr htok = IntPtr.Zero;
            OpenProcessToken(hproc, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, ref htok);
            tp.Count = 1;
            tp.Luid = 0;
            tp.Attr = SE_PRIVILEGE_ENABLED;
            LookupPrivilegeValue(null, SE_SHUTDOWN_NAME, ref tp.Luid);
            AdjustTokenPrivileges(htok, false, ref tp, 0, IntPtr.Zero, IntPtr.Zero);
            ExitWindowsEx(ExitWindows.ShutDown, ShutdownReason.MajorOther);
        }
        [DllImport("kernel32.dll", ExactSpelling = true)]
        private static extern IntPtr GetCurrentProcess();

        [DllImport("advapi32.dll", ExactSpelling = true, SetLastError = true)]
        private static extern bool OpenProcessToken(IntPtr h, int acc, ref IntPtr phtok);

        [DllImport("advapi32.dll", SetLastError = true)]
        private static extern bool LookupPrivilegeValue(string host, string name, ref long pluid);

        [DllImport("advapi32.dll", ExactSpelling = true, SetLastError = true)]
        private static extern bool AdjustTokenPrivileges(IntPtr htok, bool disall, ref TokPriv1Luid newst, int len, IntPtr prev, IntPtr relen);

        [DllImport("user32.dll")]
        private static extern bool ExitWindowsEx(ExitWindows uFlags, ShutdownReason dwReason);
    }
}